import sys
import time
from urllib import urlencode
import urllib2
import requests
import json
import logging
import subprocess

import settings
import connector.connector

log = logging.getLogger(settings.log_name_applog)


class Error(Exception):
    pass


class UploadTokenExpiredError(Error):
    pass


def __download_info_parser(filepath):
# Purpose:
# encapsulate video information into dict
# Elements:
# [title, original_url, unloader, upload_date, content, additional_tags]
    filestream = open(filepath)
    json_content = json.loads(filestream.read())
    filestream.close()

    try:
        title = json_content['fulltitle'].encode()
    except UnicodeEncodeError, e:
        log.warning("unsupported encoding in title, changed into '[ENCODERR]'")
        sys.stdout.write("unsupported encoding in title, changed into '[ENCODERR]'\n")
        title = '[ENCODERROR]'

    try:
        uploader = json_content['uploader'].encode()
    except UnicodeEncodeError, e:
        log.warning("unsupported encoding in uploader, changed into 'ENCODERR'")
        sys.stdout.write("unsupported encoding in uploader, changed into 'ENCODERR'\n")
        uploader = '[ENCODERROR]'

    try:
        content = json_content['description'].encode()
    except UnicodeEncodeError, e:
        log.warning("unsupported encoding in content, changed into 'ENCODERR'")
        sys.stdout.write("unsupported encoding in content, changed into 'ENCODERR'\n")
        content = '[ENCODERROR]'

    upload_date = json_content['upload_date'].encode()
    original_url = json_content['webpage_url'].encode().replace('www.youtube.com', 'youtube.com')

    result = {
        'title': title,
        'uploader': uploader,
        'upload_date': upload_date,
        'content': content,
        'original_url': original_url
        }

    return result


def __retrieve_upload_content(info):
    content = 'Uploaded on %s\n%s\n\nCredit to: %s\nOriginal url: %s' % (info['upload_date'],
                                                                         info['content'],
                                                                         info['uploader'],
                                                                         info['original_url'])

    return content


def __retrieve_upload_result(url):
    result = ''
    content_prev = ''
    status  = 'init'
    status_flag = True

    while status_flag:
        request = urllib2.urlopen(url)
        content = request.read()
        content_dict = json.loads(content)

        if content_dict['status'] == settings.tudou_api_upload_status_fail:
            sys.stdout.write('upload failed.\n')
            status_flag = False
            status = content_dict['status']

        elif content_dict['status'] == settings.tudou_api_upload_status_finish:
            status = settings.tudou_api_upload_status_finish
            status_flag = False

        if not content == content_prev:
            content_prev = content
            result += content
            print content

        time.sleep(settings.upload_status_refresh_interval)

    return result, status


def __get_upload_json(info):
    content = __retrieve_upload_content(info)
    parameters = {
        'app_key'        : settings.tudou_api_app_key,
        'access_token'   : settings.tudou_api_access_token,
        'title'          : info['title'],
        'tags'           : settings.tudou_api_upload_tags,
        'content'        : content,
        'channelId'      : settings.tudou_api_upload_channelid
    }
    url = settings.tudou_api_upload_url + '?' + urlencode(parameters)

    try:
        result = requests.post(url, allow_redirects=True).content

    except requests.ConnectionError, e:
        logging.warning('upload url retrieving failed. request url: %s' % url)
        return None

    except requests.RequestException, e:
        sys.stderr.write(e)
        logging.warning('upload url retrieving failed. request url: %s' % url)
        return None

    else:
        if 'error_info' in result:
            raise UploadTokenExpiredError
        else:
            return result


def __upload_json_validation(info):
    return 'itemCode' in info and 'token' in info and 'uploadUrl' in info


def __upload_validation(json_content):
    return ('content' in json_content and 'status' in json_content) and \
        (json_content['content'] is 'ok' and json_content['status'] is 'ok')


def upload_video(json_filepath, video_filepath):
    info = __download_info_parser(json_filepath)
    if info is None:
        return None, None

    upload_json = None
    output = ''
    result = ''
    status = True

    try:
        upload_json = __get_upload_json(info)

    except UploadTokenExpiredError:
        print 'Failed to uplaod - Fatal Error.'
        print settings.tudou_api_upload_emsg_expired_token
        log.warning('Failed to uplaod - Fatal Error.')
        log.warning(settings.tudou_api_upload_emsg_expired_token)

    if upload_json is None:
        sys.stderr.write('Cannot retrieve upload json, session may be blocked or token has been expired.\n')
        return None, None

    upload_dict = json.loads(upload_json)
    upload_url = upload_dict['uploadUrl']

    command = 'curl -F "action=upload" -F "file=@%s" "%s"' % (video_filepath, upload_url)

    print command
    print upload_url

    pp = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    try:
        output, status = __retrieve_upload_result(upload_url)

    except KeyboardInterrupt:
        print 'stop uploading current video: %s' % info['title']
        pass

    except Exception, e:
        print 'unexpected error when uploading: %s' % info['title']
        print e

    pp.kill()

    return output, status

    #retrieve upload status
    # -- NOT necessary - result will be sent to 'result' from subprocess
    #command = 'curl %s' % upload_url
#    try:
#        upload_result = command
#        # convert keys and values in dict into plain str from unicode str.
#
#    except Exception, e:
#        print 'unexcepted error when retrieving upload status.'
#        print e

# this should be taken care of by the output processor.
#
#    else:
#        if __upload_validation(upload_result):
#            log.info(settings.uploader_logging_file_completed_pattern  + info['original_url'])
#        else:
#            log.info(settings.uploader_logging_file_failed_pattern + info['original_url'])


if __name__ == '__main__':
    upload_video('C:/personal/workspace/vrc-video-download-tool/download/Fall 2013 UROS Competition VEX Robotics ENES 101 Group 5.info.json',
                 'C:/personal/workspace/vrc-video-download-tool/download/Fall 2013 UROS Competition VEX Robotics ENES 101 Group 5.mp4')